package com.indi.gulimall.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.indi.common.constant.OrderConstant;
import com.indi.common.constant.OrderConstant.OrderStatusEnum;
import com.indi.common.constant.SeckillConstant;
import com.indi.common.dto.OrderDTO;
import com.indi.common.dto.SeckillSkuRedisDTO;
import com.indi.common.dto.WareLockStockDTO;
import com.indi.common.dto.WareLockStockDTO.OrderItemDTO;
import com.indi.common.dto.mq.SeckillSkuDTO;
import com.indi.common.enums.BizCodeEnum;
import com.indi.common.exception.Assert;
import com.indi.common.to.MemberTO;
import com.indi.common.to.SkuStockTO;
import com.indi.common.utils.PageUtils;
import com.indi.common.utils.Query;
import com.indi.common.utils.R;
import com.indi.gulimall.order.dao.OrderDao;
import com.indi.gulimall.order.dto.MemberReceiveAddressDTO;
import com.indi.gulimall.order.dto.OrderCreateDTO;
import com.indi.gulimall.order.dto.SpuInfoDTO;
import com.indi.gulimall.order.entity.OrderEntity;
import com.indi.gulimall.order.entity.OrderItemEntity;
import com.indi.gulimall.order.entity.PaymentInfoEntity;
import com.indi.gulimall.order.feign.CartFeignService;
import com.indi.gulimall.order.feign.MemberFeignService;
import com.indi.gulimall.order.feign.ProductFeignService;
import com.indi.gulimall.order.feign.WareFeignService;
import com.indi.gulimall.order.interceptor.LoginUserInterceptor;
import com.indi.gulimall.order.mapstruct.OrderCovertBasic;
import com.indi.gulimall.order.service.OrderItemService;
import com.indi.gulimall.order.service.OrderService;
import com.indi.gulimall.order.service.PaymentInfoService;
import com.indi.gulimall.order.vo.*;
import com.indi.gulimall.order.vo.OrderConfirmVO.MemberAddressVO;
import com.indi.gulimall.order.vo.OrderConfirmVO.OrderItemVO;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

//@RabbitListener(queues = {"hello-java-queue"})  // queues：声明需要监听的所有队列
@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {
    private ThreadLocal<OrderSubmitVO> threadLocal = new ThreadLocal<>();

    private ThreadLocal<SeckillOrderSubmitVO> seckillThreadLocal = new ThreadLocal<>();

    @Resource
    private MemberFeignService memberFeignService;

    @Resource
    private CartFeignService cartFeignService;

    @Resource
    private WareFeignService wareFeignService;

    @Resource
    private ProductFeignService productFeignService;

    @Resource
    private OrderItemService orderItemService;

    @Resource
    private PaymentInfoService paymentInfoService;

    @Resource
    private ThreadPoolExecutor executor;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public OrderConfirmVO getConfirmInfo() throws ExecutionException, InterruptedException {
        OrderConfirmVO orderConfirmVO = new OrderConfirmVO();
        MemberTO memberTO = LoginUserInterceptor.threadLocal.get();
        // 共享主线程中拿到原请求数据
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

        CompletableFuture<Void> memberFuture = CompletableFuture.runAsync(() -> {
            // 根据会员id查询地址
            // 重新设置异步任务的请求数据
            RequestContextHolder.setRequestAttributes(requestAttributes);
            R r = memberFeignService.getAddress(memberTO.getId());
            if (r.getCode() == 0) {
                List<MemberAddressVO> address = r.getData(new TypeReference<List<MemberAddressVO>>() {
                });
                orderConfirmVO.setAddress(address);
            }
        }, executor);

        // 获取当前用户的所有选中购物项
        CompletableFuture<Void> cartFuture = CompletableFuture.runAsync(() -> {
            // 重新设置异步任务的请求数据
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<OrderItemVO> orderItems = cartFeignService.getCurrentUserCartItems();
            orderConfirmVO.setItems(orderItems);

        }, executor).thenRunAsync(() -> {
            // 查询所有购物车商品的库存信息
            List<OrderItemVO> items = orderConfirmVO.getItems();
            List<Long> skuIds = items.stream().map(OrderItemVO::getSkuId).collect(Collectors.toList());
            R r = wareFeignService.stockOrNot(skuIds);
            if (r.getCode() == 0) {
                List<SkuStockTO> SkuStockTOs = r.getData(new TypeReference<List<SkuStockTO>>() {
                });
                Map<Long, Boolean> stocks = SkuStockTOs.stream().collect(Collectors.toMap(SkuStockTO::getSkuId,
                        SkuStockTO::getStockOrNot));
                orderConfirmVO.setStocks(stocks);
            }
        }, executor);

        CompletableFuture.allOf(memberFuture, cartFuture).get();

        // 设置用户积分
        orderConfirmVO.setIntegration(memberTO.getIntegration());

        // 计算应付、总付
        setAggs(orderConfirmVO);

        // 防重令牌
        String orderToken = UUID.randomUUID().toString().replace("-", "");
        orderConfirmVO.setOrderToken(orderToken);
        stringRedisTemplate.opsForValue().set(OrderConstant.ORDER_TOKEN_PREFIX + memberTO.getId(), orderToken, 30,
                TimeUnit.MINUTES);

        return orderConfirmVO;
    }

    @Override
    @Transactional
//    @GlobalTransactional
    public OrderSubmitResponseVO submitOrder(OrderSubmitVO orderSubmitVO) {
        threadLocal.set(orderSubmitVO);
        String orderToken = orderSubmitVO.getOrderToken();
        OrderSubmitResponseVO responseVO = new OrderSubmitResponseVO();
        MemberTO memberTO = LoginUserInterceptor.threadLocal.get();

        // 这段脚本的意思是，如果获取key对应的value是传过来的值，那就调用删除方法返回1，否则返回0
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        // 原子删锁
        /*
            实现RedisScript接口的实现类(脚本内容,执行完之后的返回值类型)
            一个存key的list
            要对比的value
         */
        Long result = stringRedisTemplate.execute(new DefaultRedisScript<>(script, Long.class),
                Arrays.asList(OrderConstant.ORDER_TOKEN_PREFIX + memberTO.getId()), orderToken);
        // 1、校验令牌
        if (result == 0L) {
            // 验证失败
            responseVO.setCode(1);
        } else {
            // 验证成功
            // 2、创建订单、订单项等信息
            OrderCreateDTO orderCreateDTO = createOrder();

            // 3、比价
            // 考虑到最终金额可能会有多位小数的问题，此处选择算差价
            BigDecimal payAmount = orderCreateDTO.getOrder().getPayAmount();
            BigDecimal payPrice = orderSubmitVO.getPayPrice();
            if (Math.abs(payAmount.subtract(payPrice).doubleValue()) < 0.01) {
                // 对比成功
                // 4、将准备好的订单信息保存到数据库
                saveOrderAndItems(orderCreateDTO);

                // 5、库存锁定
                WareLockStockDTO wareLockStockDTO = new WareLockStockDTO();
                wareLockStockDTO.setOrderSn(orderCreateDTO.getOrder().getOrderSn());
                List<OrderItemDTO> orderItemDTOs = orderCreateDTO.getOrderItems().stream().map(orderItem ->
                        OrderCovertBasic.INSTANCE.orderItemToWareLockStockDTO(orderItem)
                ).collect(Collectors.toList());
                wareLockStockDTO.setItems(orderItemDTOs);

                R r = wareFeignService.lockStock(wareLockStockDTO);

                responseVO.setOrder(orderCreateDTO.getOrder());
                Assert.isTrue(r.getCode() == 0, BizCodeEnum.HAS_STOCK_EXCEPTION);
                responseVO.setCode(0);

                // 库存全部锁定成功，可以支付了
                // 测试库存自动解锁，往外抛个异常
//                throw new BusinessException(BizCodeEnum.UNKNOWN_EXCEPTION);

                // 给MQ发消息，让它定时取消订单
                rabbitTemplate.convertAndSend(OrderConstant.ORDER_EVENT_EXCHANGE,
                        OrderConstant.ORDER_CREATE_ORDER_ROUTING_KEY, orderCreateDTO.getOrder());
            } else {
                // 金额对比失败
                responseVO.setCode(2);
            }
        }
        return responseVO;
    }

    @Override
    public OrderEntity getOrderByOrderSn(String orderSn) {
        return this.getOne(new QueryWrapper<OrderEntity>().eq("order_sn", orderSn));
    }

    @Override
    @Transactional
    public void closeOrder(OrderEntity order) {
        // 去数据库查询最新的订单信息
        OrderEntity currentOrder = this.getById(order.getId());

        // 如果是未付款的订单，就可以取消
        if (currentOrder.getStatus() == OrderStatusEnum.TO_BE_PAID.getCode()) {
            OrderEntity newOrder = new OrderEntity();
            newOrder.setId(order.getId());
            newOrder.setStatus(OrderStatusEnum.CANCELLED.getCode());
            this.updateById(newOrder);
            OrderDTO orderDTO = OrderCovertBasic.INSTANCE.orderToOrderDTO(currentOrder);
            rabbitTemplate.convertAndSend(OrderConstant.ORDER_EVENT_EXCHANGE, OrderConstant.ORDER_RELEASE_OTHER_ROUTING_KEY,
                    orderDTO);
        }
    }

    @Override
    public PayVO getOrderPayInfo(String orderSn) {
        OrderEntity order = getOrderByOrderSn(orderSn);
        PayVO payVO = new PayVO();
        payVO.setOutTradeNo(orderSn);

        List<OrderItemEntity> orderItems = orderItemService.listByOrderSn(orderSn);
        payVO.setSubject(orderItems.get(0).getSkuName());
        payVO.setTotalAmount(order.getPayAmount().setScale(2, BigDecimal.ROUND_UP).toString());
        payVO.setBody(orderItems.get(0).getSkuAttrsVals());

        return payVO;
    }

    @Override
    public PageUtils queryOrderPage(Map<String, Object> params) {
        // 获取当前登录用户的信息
        MemberTO memberTO = LoginUserInterceptor.threadLocal.get();

        // 分页查询当前用户的所有订单
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>().eq("member_id", memberTO.getId()).orderByDesc("id")
        );

        // 查询每个订单的订单项
        List<OrderEntity> orders = page.getRecords().stream().map(order -> {
            List<OrderItemEntity> orderItems = orderItemService.listByOrderSn(order.getOrderSn());
            order.setOrderItems(orderItems);
            return order;
        }).collect(Collectors.toList());

        page.setRecords(orders);
        return new PageUtils(page);
    }

    @Override
    public String handlePayResult(PayAsyncVO payAsyncVO) {
        String tradeStatus = payAsyncVO.getTrade_status();

        // 保存交易流水
        PaymentInfoEntity paymentInfo = new PaymentInfoEntity();
        paymentInfo.setOrderSn(payAsyncVO.getOut_trade_no());
        paymentInfo.setAlipayTradeNo(payAsyncVO.getTrade_no());
        paymentInfo.setPaymentStatus(tradeStatus);
        paymentInfo.setCallbackTime(payAsyncVO.getNotify_time());
        paymentInfoService.save(paymentInfo);

        if (tradeStatus.equals("TRADE_SUCCESS") || tradeStatus.equals("TRADE_FINISHED")) {
            // 修改订单状态
            this.updateOrderStatus(payAsyncVO.getOut_trade_no(), OrderStatusEnum.PAID.getCode());
        }
        return "success";
    }

    @Override
    public void updateOrderStatus(String orderSn, int status) {
        this.update(new UpdateWrapper<OrderEntity>().set("status", status).eq("order_sn", orderSn));
    }

    @Override
    public SeckillOrderConfirmVO getSeckillOrderInfo(SeckillSkuDTO seckillSkuDTO) {
        MemberTO memberTO = LoginUserInterceptor.threadLocal.get();
        StringBuilder strBuilder = new StringBuilder(SeckillConstant.SECKILL_ABSENT_PREFIX);
        strBuilder.append(memberTO.getId()).append("_").append(seckillSkuDTO.getPromotionSessionId()).append("_")
                .append(seckillSkuDTO.getSkuId());
        String value = stringRedisTemplate.opsForValue().get(strBuilder.toString());
        // 当前用户根本就没抢到商品
        if (StringUtils.isEmpty(value)) {
            return null;
        }
        // 从缓存中拿秒杀商品的基础信息
        String redisKey = seckillSkuDTO.getPromotionSessionId() + "_" + seckillSkuDTO.getSkuId();
        BoundHashOperations<String, String, String> skusOperations = stringRedisTemplate.boundHashOps(SeckillConstant
                .SECKILL_SKU_PREFIX);
        String jsonStr = skusOperations.get(redisKey);
        SeckillSkuRedisDTO seckillSkuRedisDTO = JSON.parseObject(jsonStr, SeckillSkuRedisDTO.class);

        if (seckillSkuDTO.getNum() > seckillSkuRedisDTO.getSeckillSkuRelationDTO().getSeckillLimit()) {
            return null;
        }

        // 准备要显示给用户的秒杀数据
        SeckillOrderConfirmVO seckillConfirmVO = new SeckillOrderConfirmVO();

        // 根据会员id查询地址
        R r = memberFeignService.getAddress(memberTO.getId());
        if (r.getCode() == 0) {
            List<SeckillOrderConfirmVO.MemberAddressVO> address =
                    r.getData(new TypeReference<List<SeckillOrderConfirmVO.MemberAddressVO>>() {
                    });
            seckillConfirmVO.setAddress(address);
        }
        seckillConfirmVO.setOrderSn(seckillSkuDTO.getOrderSn());
        seckillConfirmVO.setTitle(seckillSkuRedisDTO.getSkuInfoDTO().getSkuTitle());
        seckillConfirmVO.setImage(seckillSkuRedisDTO.getSkuInfoDTO().getSkuDefaultImg());
        seckillConfirmVO.setPrice(seckillSkuRedisDTO.getSeckillSkuRelationDTO().getSeckillPrice());
        seckillConfirmVO.setNum(seckillSkuDTO.getNum());
        seckillConfirmVO.setPromotionSessionId(seckillSkuDTO.getPromotionSessionId());
        seckillConfirmVO.setSkuId(seckillSkuDTO.getSkuId());
        seckillConfirmVO.setSkuAttr(seckillSkuRedisDTO.getSkuAttr());

//        // 设置用户积分
        seckillConfirmVO.setIntegration(memberTO.getIntegration());
//
//        // 计算应付、总付
        BigDecimal totalPrice = seckillConfirmVO.getPrice().multiply(new BigDecimal(seckillSkuDTO.getNum()));
        seckillConfirmVO.setTotalPrice(totalPrice);
        // 计算运费，如果单笔订单金额大于等于包邮金额，则免运费，否则运费8元
        seckillConfirmVO.setFreight(totalPrice.compareTo(OrderConstant.FREE_FREIGHT_PRICE) >= 0 ? BigDecimal.ZERO
                : OrderConstant.FREIGHT);
        seckillConfirmVO.setPayPrice(seckillConfirmVO.getTotalPrice().add(seckillConfirmVO.getFreight()));
        return seckillConfirmVO;
    }

    @Override
    public OrderSubmitResponseVO submitSeckillOrder(SeckillOrderSubmitVO seckillOrderSubmitVO) {
        R r = memberFeignService.getReceiveAddressInfo(seckillOrderSubmitVO.getAddrId());
        if (r.getCode() == 0) {
            MemberReceiveAddressDTO receiveAddressInfo = r.getData("memberReceiveAddress",
                    new TypeReference<MemberReceiveAddressDTO>() {
                    });
            // 设置收货人信息
            OrderEntity order = OrderCovertBasic.INSTANCE.MemberReceiveAddressDTOToOrder(receiveAddressInfo);
            order.setOrderSn(seckillOrderSubmitVO.getOrderSn());

            OrderEntity oldOrder = this.getOrderByOrderSn(seckillOrderSubmitVO.getOrderSn());
            order.setId(oldOrder.getId());
            this.updateById(order);

            OrderSubmitResponseVO responseVO = new OrderSubmitResponseVO();
            responseVO.setOrder(oldOrder);
            responseVO.setCode(0);
            return responseVO;
        }
        return null;
    }

    @Override
    public void createSeckillOrder(SeckillSkuDTO seckillSkuDTO) {
        OrderEntity order = buildSeckillOrder(seckillSkuDTO.getOrderSn());
        BigDecimal totalPrice = seckillSkuDTO.getPrice().multiply(new BigDecimal(seckillSkuDTO.getNum()));
        order.setTotalAmount(totalPrice);
        // 计算运费，如果单笔订单金额大于等于包邮金额，则免运费，否则运费8元
        order.setFreightAmount(totalPrice.compareTo(OrderConstant.FREE_FREIGHT_PRICE) >= 0 ? BigDecimal.ZERO
                : OrderConstant.FREIGHT);
        order.setPayAmount(order.getTotalAmount().add(order.getFreightAmount()));
        order.setMemberId(seckillSkuDTO.getMemberId());
        order.setIntegration(totalPrice.intValue());
        order.setGrowth(totalPrice.intValue());

        OrderItemEntity orderItem = buildSeckillOrderItem(seckillSkuDTO);
        this.save(order);
        orderItemService.save(orderItem);

        // 超时未支付，需要取消秒杀订单
        rabbitTemplate.convertAndSend(OrderConstant.ORDER_EVENT_EXCHANGE,
                OrderConstant.ORDER_CREATE_ORDER_ROUTING_KEY, seckillSkuDTO);
    }

    @Override
    public void closeSeckillOrder(SeckillSkuDTO seckillSkuDTO) {
        // 去数据库查询最新的订单信息
        OrderEntity currentOrder = this.getOrderByOrderSn(seckillSkuDTO.getOrderSn());

        // 如果是未付款的订单，就可以取消
        if (currentOrder.getStatus() == OrderStatusEnum.TO_BE_PAID.getCode()) {
            OrderEntity newOrder = new OrderEntity();
            newOrder.setId(currentOrder.getId());
            newOrder.setStatus(OrderStatusEnum.CANCELLED.getCode());
            this.updateById(newOrder);
            rabbitTemplate.convertAndSend(OrderConstant.ORDER_EVENT_EXCHANGE,
                    OrderConstant.ORDER_SECKILL_RELEASE_OTHER_ROUTING_KEY,
                    seckillSkuDTO);
        }
    }


    /**
     * 构建秒杀订单基本数据
     *
     * @param orderSn
     * @return
     */
    private OrderEntity buildSeckillOrder(String orderSn) {
        // 获取用户选择的收货信息
        OrderEntity order = new OrderEntity();
        order.setOrderSn(orderSn);
        order.setAutoConfirmDay(7);
        order.setStatus(OrderStatusEnum.TO_BE_PAID.getCode());

        order.setPromotionAmount(BigDecimal.ZERO);
        order.setIntegrationAmount(BigDecimal.ZERO);
        order.setCouponAmount(BigDecimal.ZERO);

        return order;
    }

    /**
     * 构建秒杀订单购物项
     *
     * @param seckillSkuDTO
     * @return
     */
    private OrderItemEntity buildSeckillOrderItem(SeckillSkuDTO seckillSkuDTO) {
        OrderItemEntity orderItem = new OrderItemEntity();
//        orderItem.setOrderId(0L);
        orderItem.setOrderSn(seckillSkuDTO.getOrderSn());

        // 商品的SPU信息
        R r = productFeignService.info(seckillSkuDTO.getSkuId());
        if (r.getCode() == 0) {
            SpuInfoDTO spuInfoDTO = r.getData(new TypeReference<SpuInfoDTO>() {
            });
            orderItem.setSpuId(spuInfoDTO.getId());
            orderItem.setSpuName(spuInfoDTO.getSpuName());
            orderItem.setSpuBrand(spuInfoDTO.getBrandId().toString());
            orderItem.setCategoryId(spuInfoDTO.getCategoryId());
        }


        // 商品的sku信息
        orderItem.setSkuId(seckillSkuDTO.getSkuId());
        orderItem.setSkuName(seckillSkuDTO.getTitle());
        orderItem.setSkuPic(seckillSkuDTO.getImage());
        orderItem.setSkuPrice(seckillSkuDTO.getPrice());
        orderItem.setSkuQuantity(seckillSkuDTO.getNum());
        // 将销售属性的List转换为String
        StringBuilder listStr = new StringBuilder();
        for (String attr : seckillSkuDTO.getSkuAttr()) {
            listStr.append(attr + ";");
        }
        orderItem.setSkuAttrsVals(listStr.toString());


        // 优惠信息[不做，直接赋0]
        orderItem.setCouponAmount(BigDecimal.ZERO);
        orderItem.setPromotionAmount(BigDecimal.ZERO);
        orderItem.setIntegrationAmount(BigDecimal.ZERO);

        // 最终价格：总额 - 所有优惠
        BigDecimal totalPrice = seckillSkuDTO.getPrice().multiply(new BigDecimal(seckillSkuDTO.getNum()));
        BigDecimal realAmount = totalPrice.subtract(orderItem.getCouponAmount())
                .subtract(orderItem.getPromotionAmount()).subtract(orderItem.getIntegrationAmount());
        orderItem.setRealAmount(realAmount);

        // 积分信息
        orderItem.setGiftIntegration(totalPrice.intValue());
        orderItem.setGiftGrowth(totalPrice.intValue());

        return orderItem;
    }


    /**
     * 保存订单、订单项
     *
     * @param orderCreateDTO
     */
    private void saveOrderAndItems(OrderCreateDTO orderCreateDTO) {
        this.save(orderCreateDTO.getOrder());
        orderItemService.saveBatch(orderCreateDTO.getOrderItems());
    }

    /**
     * 创建订单（总）
     *
     * @return
     */
    private OrderCreateDTO createOrder() {
        OrderCreateDTO orderCreateDTO = new OrderCreateDTO();
        // 订单号
        String orderSn = IdWorker.getTimeId();

        // 1、构建订单基本数据
        OrderEntity order = buildOrder(orderSn);

        // 2、获取购物车中的所有选中购物项
        List<OrderItemEntity> orderItems = buildOrderItems(order.getOrderSn());

        // 3、计算价格等聚合信息
        computeOrderAggs(order, orderItems);

        orderCreateDTO.setOrder(order);
        orderCreateDTO.setOrderItems(orderItems);
        return orderCreateDTO;
    }

    /**
     * 构建订单基本数据
     *
     * @param orderSn
     * @return
     */
    private OrderEntity buildOrder(String orderSn) {
        OrderSubmitVO orderSubmitVO = threadLocal.get();
        MemberTO memberTO = LoginUserInterceptor.threadLocal.get();
        // 获取用户选择的收货信息
        R r = memberFeignService.getReceiveAddressInfo(orderSubmitVO.getAddrId());
        OrderEntity order = new OrderEntity();
        if (r.getCode() == 0) {
            MemberReceiveAddressDTO receiveAddressInfo = r.getData("memberReceiveAddress",
                    new TypeReference<MemberReceiveAddressDTO>() {
                    });
            // 设置收货人信息
            order = OrderCovertBasic.INSTANCE.MemberReceiveAddressDTOToOrder(receiveAddressInfo);

            order.setOrderSn(orderSn);
            order.setAutoConfirmDay(7);
            order.setStatus(OrderStatusEnum.TO_BE_PAID.getCode());

            order.setMemberId(memberTO.getId());
        }
        return order;
    }

    /**
     * 根据购物车的选中项创建订单项
     *
     * @return
     */
    private List<OrderItemEntity> buildOrderItems(String orderSn) {
        // 这个方法会更新购物车中所有商品的最新价格，这也是下单流程中最后一次确定购物项的价格了
        List<OrderItemVO> OrderItemVOs = cartFeignService.getCurrentUserCartItems();
        if (CollectionUtils.isNotEmpty(OrderItemVOs)) {
            List<OrderItemEntity> orderItems = OrderItemVOs.stream().map(item -> {
                OrderItemEntity orderItem = buildOrderItem(item);
                orderItem.setOrderSn(orderSn);
                return orderItem;
            }).collect(Collectors.toList());
            return orderItems;
        }
        return null;
    }

    /**
     * 构建某一个订单购物项
     *
     * @param orderItemVO
     * @return
     */
    private OrderItemEntity buildOrderItem(OrderItemVO orderItemVO) {
        OrderItemEntity orderItem = new OrderItemEntity();
//        orderItem.setOrderId(0L);

        // 商品的SPU信息
        R r = productFeignService.info(orderItemVO.getSkuId());
        if (r.getCode() == 0) {
            SpuInfoDTO spuInfoDTO = r.getData(new TypeReference<SpuInfoDTO>() {
            });
            orderItem.setSpuId(spuInfoDTO.getId());
            orderItem.setSpuName(spuInfoDTO.getSpuName());
            orderItem.setSpuBrand(spuInfoDTO.getBrandId().toString());
            orderItem.setCategoryId(spuInfoDTO.getCategoryId());
        }


        // 商品的sku信息
        orderItem.setSkuId(orderItemVO.getSkuId());
        orderItem.setSkuName(orderItemVO.getTitle());
        orderItem.setSkuPic(orderItemVO.getImage());
        orderItem.setSkuPrice(orderItemVO.getPrice());
        orderItem.setSkuQuantity(orderItemVO.getCount());

        // 将销售属性的List转换为String
        StringBuilder listStr = new StringBuilder();
        for (String attr : orderItemVO.getSkuAttr()) {
            listStr.append(attr + ";");
        }
        orderItem.setSkuAttrsVals(listStr.toString());


        // 优惠信息[不做，直接赋0]
        orderItem.setCouponAmount(BigDecimal.ZERO);
        orderItem.setPromotionAmount(BigDecimal.ZERO);
        orderItem.setIntegrationAmount(BigDecimal.ZERO);

        // 最终价格：总额 - 所有优惠
        BigDecimal totalPrice = orderItemVO.getPrice().multiply(new BigDecimal(orderItemVO.getCount()));
        BigDecimal realAmount = totalPrice.subtract(orderItem.getCouponAmount())
                .subtract(orderItem.getPromotionAmount()).subtract(orderItem.getIntegrationAmount());
        orderItem.setRealAmount(realAmount);

        // 积分信息
        orderItem.setGiftIntegration(totalPrice.intValue());
        orderItem.setGiftGrowth(totalPrice.intValue());

        return orderItem;
    }

    /**
     * 计算订单最终的聚合信息
     *
     * @param order
     * @param orderItems
     */
    private void computeOrderAggs(OrderEntity order, List<OrderItemEntity> orderItems) {
        BigDecimal totalAmount = BigDecimal.ZERO;   // 订单总金额

        BigDecimal promotionAmount = BigDecimal.ZERO;   // 商品促销分解金额
        BigDecimal integrationAmount = BigDecimal.ZERO; // 积分优惠分解金额
        BigDecimal couponAmount = BigDecimal.ZERO;  // 优惠券优惠分解金额

        int integration = 0;    // 赠送积分
        int growth = 0; // 赠送成长值

        for (OrderItemEntity orderItem : orderItems) {
            totalAmount = totalAmount.add(orderItem.getRealAmount());
            promotionAmount = promotionAmount.add(orderItem.getPromotionAmount());
            integrationAmount = integrationAmount.add(orderItem.getIntegrationAmount());
            couponAmount = couponAmount.add(orderItem.getCouponAmount());
            integration += orderItem.getGiftIntegration();
            growth += orderItem.getGiftGrowth();
        }

        order.setTotalAmount(totalAmount);
        order.setFreightAmount(totalAmount.compareTo(OrderConstant.FREE_FREIGHT_PRICE) >= 0 ? BigDecimal.ZERO
                : OrderConstant.FREIGHT);
        order.setPayAmount(totalAmount.add(order.getFreightAmount()));
        order.setPromotionAmount(promotionAmount);
        order.setIntegrationAmount(integrationAmount);
        order.setCouponAmount(couponAmount);
        order.setIntegration(integration);
        order.setGrowth(growth);
    }

    /**
     * 订单确认页：计算订单总额、应付价格
     *
     * @param orderConfirmVO
     */
    private void setAggs(OrderConfirmVO orderConfirmVO) {
        List<OrderItemVO> items = orderConfirmVO.getItems();
        BigDecimal totalPrice = BigDecimal.ZERO;
        Integer totalCount = 0;
        for (OrderItemVO item : items) {
            // 为避免redis数据库中的商品存放时间过长，导致价格变更，此处必须重新计算价格
            if (item != null) {
                totalPrice = totalPrice.add(item.getPrice().multiply(new BigDecimal(item.getCount())));
                totalCount += item.getCount();
            }
        }
        orderConfirmVO.setTotalPrice(totalPrice);
        orderConfirmVO.setTotalCount(totalCount);
        // 计算运费，如果单笔订单金额大于等于包邮金额，则免运费，否则运费8元
        orderConfirmVO.setFreight(totalPrice.compareTo(OrderConstant.FREE_FREIGHT_PRICE) >= 0 ? BigDecimal.ZERO
                : OrderConstant.FREIGHT);
        orderConfirmVO.setPayPrice(orderConfirmVO.getTotalPrice().add(orderConfirmVO.getFreight()));

    }

    /**
     * 1、监听hello-java-queue的消息
     * <p>
     * 2、假设订单服务启动多个，这3个服务同时都来监听这个消息队列，是都能收到？还是只有1个能收到？
     * 结果：每条消息只能有一个客户端收到，单元测试可能会出现疑似丢失消息的情况，是因为单元测
     * 试也相当于一个客户端，所以有一些消息发到了单元测试里
     * <p>
     * 3、假设业务处理很耗时，那么在处理期间，能否接收到其它消息？
     * 结果：只有一个消息完全处理完，方法运行结束，才可以接收下一个消息
     *
     * @param message 原生消息
     * @param reason  发的时候用的什么类型，接收的时候就用什么类型
     * @param channel 当前传输数据的通道
     */
//    @RabbitHandler  // 指明哪个方法接收消息
//    public void receiveMessage(Message message,
//                               OrderReturnReasonEntity reason,
//                               Channel channel) {
//        // 消息体
//        byte[] body = message.getBody();
//
//        // 消息头属性信息
//        MessageProperties messageProperties = message.getMessageProperties();
//
//        // 1、模拟执行业务时间超长
////        try{
////            TimeUnit.SECONDS.sleep(3);
////        }catch(InterruptedException e){
////            e.printStackTrace();
////        }
////        System.out.println("原生消息：" + message);
////        System.out.println("消息类型：" + reason);
//
//
//        /*
//            获取消息标签
//
//            deliveryTag：当前消息派发的标签数字，通道(channel)内自增
//            multiple: 是否为批量确认
//         */
//        long deliveryTag = message.getMessageProperties().getDeliveryTag();
//        System.out.println("deliveryTag: " + deliveryTag);
//
//        try {
//            /*
//               手动签收消息
//
//               deliveryTag: 消息标签
//               multiple: 是否批量签收
//             */
//            if (deliveryTag % 2 == 0) {
//                channel.basicAck(deliveryTag, false);
//                System.out.println("签收消息：" + deliveryTag);
//            } else {
//                /*
//                    拒收消息
//                    nack()用于否定确认
//                    reject()用于否定确认；同上，但不能批量
//
//                    deliveryTag: 消息标签
//                    multiple: 是否批量拒收
//                    requeue: 拒收之后，是否重新进入队列
//                        true: 发回MQ服务器，重新进入队列
//                        false: 直接丢弃
//                 */
//                channel.basicNack(deliveryTag, false, true);
//                System.out.println("拒收消息：" + deliveryTag);
//            }
//        } catch (IOException e) {
//            // 可能会网络中断，触发异常
//            e.printStackTrace();
//        }
//    }

    /**
     * 接收什么order类型的消息
     *
     * @param order 类型
     */
//    @RabbitHandler
//    public void receiveMessage2(OrderEntity order) {
//        System.out.println("消息类型：" + order);
//    }


}